package edu.hawaii.halealohacli.jcev.processor;

import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Map;
import org.junit.Test;
import edu.hawaii.halealohacli.jcev.command.Command;

/**
 * Tests the functionality of the CommandProcessor class and its methods.
 * @author Christopher Foo
 *
 */
public class TestCommandProcessor {
  
  /**
   * The CommandProcessor class to perform tests on.
   */
  CommandProcessor processor = new CommandProcessor ();
  
  /**
   * Checks that the map generated by the generateMap method is as expected (it is called by
   * the constructor).
   */
  @Test
  public void testGenerateMap() {
    Map<String, Command> commands = processor.getCommands();
    
    //Check size of the map
    assertTrue("Map is at least the default size of 6(could be larger if system has been expanded)",
               commands.size() >= 6);
    
    //Check that map contains all default commands
    assertTrue("Map contains default command \"current-power\"",
               commands.containsKey("current-power"));
    assertTrue("Map contains default command \"daily-energy\"",
               commands.containsKey("daily-energy"));
    assertTrue("Map contains default command \"energy-since\"",
               commands.containsKey("energy-since"));
    assertTrue("Map contains default command \"rank-towers\"",
               commands.containsKey("rank-towers"));
    assertTrue("Map contains default command \"help\"", commands.containsKey("help"));
    assertTrue("Map contains default command \"quit\"", commands.containsKey("quit"));
  }
  
  /**
   * Tests that the commands map cannot be changed through the map retrieved by the getCommands
   * method.
   */
  @Test
  public void testImmutability() {
    Map<String, Command> commands = processor.getCommands();
    
    //Attempt to destructively modify the map, but there should be no change
    commands.clear();
    assertTrue("CommandProcessor map should be unchanged after clear",
               processor.getCommands().size() >= 6);
  }
  
  /**
   * Test that the execute method catches the ExitException and throws it to pass it to the next
   * level (the Control class).
   */
  @Test
  public void testExit() {
    boolean caught = false;
    try {
      processor.execute(null, "quit", "");
    }
    catch (ExitException e) {
      caught = true;
    }
    catch (Exception e) {
      fail("Threw exception when given valid command.");
    }
    assertTrue("Should have caught ExitException from successful quit command call", caught);
  }
  
  /**
   * Test that execute throws an exception when an invalid command is called.
   */
  @Test
  public void testInvalidCommand() {
    boolean caught = false;
    try {
      processor.execute(null, "FAKE-COMMAND", "");
    }
    catch (ExitException e) {
      fail("Threw ExitException on invalid command.");
    }
    catch (Exception e) {
      caught = true;
    }
    assertTrue("Should have caught Exception from invalid command call", caught);
  }
}
